from django.db import models


def create_dynamic_model(name, base_class=None, fields=None, options=None,
                         admin_opts=None, app_label=None, module=None):
    """
    Based on code from http://code.djangoproject.com/wiki/DynamicModels
    """
    # TODO: Improve docstring
    # TODO: Fix styling
    if base_class is None:
        base_class = models.Model
        # Using type('Meta', ...) gives a dictproxy error during model creation
        class Meta:
            pass
    else:
        class Meta(base_class.Meta):
            pass

    if app_label:
        # app_label must be set using the Meta inner class
        setattr(Meta, 'app_label', app_label)

    # Update Meta with any options that were provided
    if options is not None:
        for key, value in options.iteritems():
            setattr(Meta, key, value)

    module = module or ''
    # Set up a dictionary to simulate declarations within a class
    attrs = {'__module__': module, 'Meta': Meta}

    # Add in any fields that were provided
    if fields:
        attrs.update(fields)

    # Create the class, which automatically triggers ModelBase processing
    model = type(name, (base_class,), attrs)

    # Create an Admin class if admin options were provided
    if admin_opts is not None:
        class Admin(admin.ModelAdmin):
            pass
        for key, value in admin_opts:
            setattr(Admin, key, value)
        admin.site.register(model, Admin)

    return model


def get_childs_own_fields(child_class, parent_class, also_blacklist_fields=None):
    # TODO: Insert docstring

    # Sanity check
    if not issubclass(parent_class, models.Model):
        raise TypeError("'%s' is not a subclass of django.db.models.Model" % parent_class) 
    if not issubclass(child_class, parent_class):
        raise TypeError("'%s' is not a subclass of %s" % (child_class, parent_class)) 
    
    child_fields = child_class._meta.get_all_field_names()
    blacklist_fields = parent_class._meta.get_all_field_names()
    blacklist_fields.append(child_class._meta.pk.name)
    if also_blacklist_fields is not None:
        blacklist_fields.extend(also_blacklist_fields)
    return filter(lambda x: x not in blacklist_fields, child_fields)
